package view_server

import (
	"bigdevops/src/common"
	"bigdevops/src/config"
	"bigdevops/src/models"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"strconv"
)

// 获取所有机器的分页api
func getResourceEcslList(c *gin.Context) {

	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	currentPage, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "100"))

	offset := 0
	limit := 0
	limit = pageSize
	if currentPage > 1 {
		offset = (currentPage - 1) * limit
	}
	// 这里只能新增 不能去掉，因为是 多种资源共用的query
	searchName := c.DefaultQuery("name", "")

	// 	数据库中拿到所有的menu列表

	objs, err := models.GetResourceEcsAll()
	if err != nil {
		sc.Logger.Error("去数据库中拿所有的机器错误",
			zap.Error(err),
		)
		common.ReqBadFailWithMessage(fmt.Sprintf("去数据库中拿所有的机器错误:%v", err.Error()), c)
		return
	}

	allIds := []int{}
	//// 遍历 role 准备menuIds 列表
	for _, obj := range objs {
		obj := obj

		// 在这里处理查询
		if searchName != "" && obj.InstanceName != searchName {
			continue
		}

		allIds = append(allIds, int(obj.ID))

		//role.MenuIds = menuIds
	}

	if len(allIds) == 0 {
		common.OkWithDetailed(allIds, "ok", c)
		return
	}
	objs, err = models.GetResourceEcsByIdsWithLimitOffset(allIds, limit, offset)
	if err != nil {
		sc.Logger.Error("limit-offset去数据库中拿所有的机器错误",
			zap.Error(err),
		)
		common.ReqBadFailWithMessage(fmt.Sprintf("limit-offset去数据库中拿所有的机器错误:%v", err.Error()), c)
		return
	}
	for _, obj := range objs {
		obj.FillFrontAllData()

	}

	resp := &ResponseResourceCommon{
		//Total: models.GetMonitorScrapePoolCount(), 因为是带了查询条件的 所以 count 不能是all 而是 过滤后的total

		Total: len(allIds),
		Items: objs,
	}

	common.OkWithDetailed(resp, "ok", c)
}

func getResourceEcsUnbindList(c *gin.Context) {
	// 拿到这个人用户 对应的role列表
	// 	遍历 role列表 找到 Menu list
	// 在拼装父子结构 返回的是数组 第一层 father 第2层children

	// 	遍历 role列表 找到 Menu list
	// 在拼装父子结构 返回的是数组 第一层 father 第2层children

	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	allEcs, err := models.GetResourceEcsAll()
	if err != nil {
		sc.Logger.Error("去数据库中拿所有的ecs错误",
			zap.Error(err),
		)
		common.ReqBadFailWithMessage(fmt.Sprintf("去数据库中拿所有的ecs错误:%v", err.Error()), c)
		return
	}

	finalList := []*models.ResourceEcs{}
	for _, ecs := range allEcs {
		ecs := ecs
		ecs.Key = fmt.Sprintf("%d", ecs.ID)
		// 它的bind_nodes为空说明未绑定
		if len(ecs.BindNodes) > 0 {
			continue
		}
		finalList = append(finalList, ecs)

	}

	common.OkWithDetailed(finalList, "ok", c)

}

func bindEscToStreeNode(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	// 校验一下 menu字段
	var reqBind models.BindResourceToStreeNodeRequest
	err := c.ShouldBindJSON(&reqBind)
	if err != nil {
		sc.Logger.Error("解析节点绑定ecs请求失败", zap.Any("reqBind", reqBind), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 在这里校验字段，是否必填，范围是否正确
	err = validate.Struct(reqBind)
	if err != nil {

		// 这里为什么要判断错误是否是 ValidationErrors
		if errors, ok := err.(validator.ValidationErrors); ok {
			common.ReqBadFailWithWithDetailed(

				gin.H{
					"翻译前": err.Error(),
					"翻译后": errors.Translate(trans),
				},
				"请求出错",
				c,
			)
			return
		}
		common.ReqBadFailWithMessage(err.Error(), c)
		return

	}

	// 先根据 nodeid 去找到node

	// 先 去db中根据id找到这个对象
	dbNode, err := models.GetStreeNodeById(reqBind.NodeId)
	if err != nil {
		sc.Logger.Error("根据id找树节点错误", zap.Any("树节点", reqBind.NodeId), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 遍历 ecs id 数组找到ecs 对象
	for _, ridStr := range reqBind.ResourceIds {
		rid, _ := strconv.Atoi(ridStr)
		dbResource, err := models.GetResourceEcsById(rid)
		if err != nil {
			sc.Logger.Error("根据id找ecs错误", zap.Any("ecs", rid), zap.Error(err))
			common.FailWithMessage(err.Error(), c)
			return
		}

		thisNode := []*models.StreeNode{}
		tmpM := map[uint]*models.StreeNode{}
		for _, node := range dbResource.BindNodes {
			node := node
			tmpM[node.ID] = node
		}
		tmpM[dbNode.ID] = dbNode
		for _, node := range tmpM {
			node := node
			thisNode = append(thisNode, node)
		}
		// 更新这个资源的 bindnodes
		err = dbResource.UpdateBindNodes(thisNode)
		if err != nil {
			sc.Logger.Error("更新ecs的绑定节点错误",
				zap.Any("ecs", rid),
				zap.Any("nodes", thisNode),
				zap.Error(err),
			)
			common.FailWithMessage(err.Error(), c)
			return
		}

	}
	common.OkWithMessage("更新成功", c)
}

func unBindEscToStreeNode(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	// 校验一下 menu字段
	var reqBind models.BindResourceToStreeNodeRequest
	err := c.ShouldBindJSON(&reqBind)
	if err != nil {
		sc.Logger.Error("解析节点解绑ecs请求失败", zap.Any("reqBind", reqBind), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 在这里校验字段，是否必填，范围是否正确
	err = validate.Struct(reqBind)
	if err != nil {

		// 这里为什么要判断错误是否是 ValidationErrors
		if errors, ok := err.(validator.ValidationErrors); ok {
			common.ReqBadFailWithWithDetailed(

				gin.H{
					"翻译前": err.Error(),
					"翻译后": errors.Translate(trans),
				},
				"请求出错",
				c,
			)
			return
		}
		common.ReqBadFailWithMessage(err.Error(), c)
		return

	}

	// 先根据 nodeid 去找到node

	// 先 去db中根据id找到这个对象
	dbNode, err := models.GetStreeNodeById(reqBind.NodeId)
	if err != nil {
		sc.Logger.Error("根据id找树节点错误", zap.Any("树节点", reqBind.NodeId), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 遍历 ecs id 数组找到ecs 对象
	for _, ridStr := range reqBind.ResourceIds {
		rid, _ := strconv.Atoi(ridStr)
		dbResource, err := models.GetResourceEcsById(rid)
		if err != nil {
			sc.Logger.Error("根据id找ecs错误", zap.Any("ecs", rid), zap.Error(err))
			common.FailWithMessage(err.Error(), c)
			return
		}

		thisNode := []*models.StreeNode{}
		tmpM := map[uint]*models.StreeNode{}
		for _, node := range dbResource.BindNodes {
			node := node
			tmpM[node.ID] = node
		}
		// 将这个树节点的id 从已经绑定的节点列表里面删除
		delete(tmpM, dbNode.ID)
		for _, node := range tmpM {
			node := node
			thisNode = append(thisNode, node)
		}
		// 更新这个资源的 bindnodes
		err = dbResource.UpdateBindNodes(thisNode)
		if err != nil {
			sc.Logger.Error("更新ecs的绑定节点错误",
				zap.Any("ecs", rid),
				zap.Any("nodes", thisNode),
				zap.Error(err),
			)
			common.FailWithMessage(err.Error(), c)
			return
		}

	}
	common.OkWithMessage("解绑成功", c)
}
